﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using PsqlDotnet.Data;
using PsqlDotnet.Enums;
using PsqlDotnet.Exceptions;
using PsqlDotnet.Model;
using PsqlDotnet.Model.Schema;
using PsqlDotnet.Model.Schema.Converters;
using PsqlDotnet.Model.Schema.Parsers;

namespace PsqlDotnet
{
    public class PsqlShell : IPsqlShell
    {
        #region Constants

        const int maxDbName = 63;
        const string PgpassVariable = "PGPPASSWORD";
        const string PgClienEncodingVariable = "PGCLIENTENCODING";
        const string PgClienEncoding = "SQL_ASCII";

        static readonly string[] RowSeparator = new string[] { "\r\n" };
        static readonly char[] ColumnSeparator = new char[] { '|' };

        #endregion

        public PsqlShell(FileInfo psqlFile, string adminLogin, string adminPassword)
        {
            if (psqlFile == null)
                throw new NullReferenceException("Illegal null-reference psql executable file");
            if (!psqlFile.Exists)
                throw new FileNotFoundException("Psql executable file not found");

            PsqlPath = psqlFile.FullName;
            AdminLogin = adminLogin;
            AdminPassword = adminPassword;

            psqlBanners = new PsqlBanners();
        }

        #region IPsqlShell Members

        public string PsqlPath { get; private set; }

        public string AdminLogin { get; private set; }

        public string AdminPassword { get; private set; }

        public void ExecuteScript(string script, string dbName)
        {
            Process p = null;

            if (script.Length > 512)
                p = InitPsqlProcess(AdminLogin, AdminPassword, script, dbName, PsqlProcessFlags.ExternalFile);
            else
                p = InitPsqlProcess(AdminLogin, AdminPassword, script, dbName);
            p.Start();
            p.WaitForExit();

            var output = p.StandardOutput.ReadToEnd();
            var error = p.StandardError.ReadToEnd();

            if (!String.IsNullOrWhiteSpace(error) && error.Contains(PsqlBanners.ErrorBanner))
                throw new PsqlException(error);
        }

        #region Database management

        public string GetVersion()
        {
            Process p = InitPsqlProcess(AdminLogin, AdminPassword, "--version", null, PsqlProcessFlags.CleanMode);
            p.Start();
            p.WaitForExit();

            var output = p.StandardOutput.ReadToEnd();
            var error = p.StandardError.ReadToEnd();

            if (!String.IsNullOrWhiteSpace(error))
                throw new PsqlException(error);

            return output.Trim(new char[] { '\r', '\n' });
        }

        public bool DatabaseExists(string dbName)
        {
            bool result = false;

            try
            {
                Process p = InitPsqlProcess(AdminLogin, AdminPassword,
                    String.Format("select count(1) from pg_database where datname = '{0}'", dbName));
                p.Start();
                p.WaitForExit();

                var output = p.StandardOutput.ReadToEnd();
                var error = p.StandardError.ReadToEnd();

                if (!String.IsNullOrWhiteSpace(error))
                    throw new PsqlException(error);

                int dbCount = Int32.Parse(output.Trim());
                result = dbCount > 0;
            }
            catch (Exception ex)
            {
                if (ex is PsqlException)
                    throw ex;
            }

            return result;
        }

        public IEnumerable<DbInfo> GetDatabasesInfo()
        {
            List<DbInfo> result = new List<DbInfo>();

            try
            {
                Process p = InitPsqlProcess(AdminLogin, AdminPassword,
                    "select pd.datname,pg_encoding_to_char(pd.encoding),pd.datallowconn,pd.datconnlimit,pct.usename " +
                    "from pg_database pd , pg_catalog.pg_user pct where pd.datdba = pct.usesysid");
                p.Start();
                p.WaitForExit();

                var output = p.StandardOutput.ReadToEnd();
                var error = p.StandardError.ReadToEnd();

                ValidatePsqlProcessOutput(output, error);

                //parse output
                string[] rows = output.Split(RowSeparator, 256, StringSplitOptions.RemoveEmptyEntries);

                foreach (var r in rows)
                {
                    string[] columns = r.Split(ColumnSeparator);

                    DbInfo dbInfo = new DbInfo()
                    {
                        Name = columns[0].Trim(),
                        Encoding = columns[1].Trim(),
                        IsConnectionAllowed = columns[2].Trim().ToLower() == "t" ? true : false,
                        ConnectionsLimit = Int32.Parse(columns[3].Trim()),
                        Owner = columns[4].Trim()
                    };

                    result.Add(dbInfo);
                }
            }
            catch (Exception ex)
            {
                if (ex is PsqlException)
                    throw ex;
            }

            return result;
        }

        public DbInfo GetDatabaseInfo(string dbName)
        {
            /*
             * Don't duplicate code due-to remote process launching issues
             * There is no difference whether we fetch info about one database or multiple
             */

            var infoList = GetDatabasesInfo();
            return infoList.Where(d => d.Name == dbName).FirstOrDefault();
        }

        public void CreateDatabase(string dbName, string ownerName)
        {
            try
            {
                if (dbName.Length > maxDbName)
                    throw new PsqlException(
                        String.Format("Too long database name. Max {0} chars allowed", maxDbName)
                        );

                Process p = InitPsqlProcess(AdminLogin, AdminPassword,
                    String.Format("create database {0} owner {1}", dbName, ownerName));
                p.Start();
                p.WaitForExit();

                var output = p.StandardOutput.ReadToEnd();
                var error = p.StandardError.ReadToEnd();

                if (!String.IsNullOrWhiteSpace(error) || !CompareBanners(output, PsqlBannersEnum.CreateDatabase))
                    throw new PsqlException(error);
            }
            catch (Exception ex)
            {
                if (ex is PsqlException)
                    throw ex;
            }
        }

        public void DropDatabase(string dbName)
        {
            try
            {
                Process p = InitPsqlProcess(AdminLogin, AdminPassword, String.Format("drop database {0}", dbName));
                p.Start();
                p.WaitForExit();

                var output = p.StandardOutput.ReadToEnd();
                var error = p.StandardError.ReadToEnd();

                if (!String.IsNullOrWhiteSpace(error) || !CompareBanners(output, PsqlBannersEnum.RemoveDatabase))
                    throw new PsqlException(error);
            }
            catch (Exception ex)
            {
                if (ex is PsqlException)
                    throw ex;
            }
        }

        #endregion

        #region User management

        public bool UserExists(string userName)
        {
            var allUsers = GetAllUsers();
            if (allUsers.Count() > 0)
            {
                if (allUsers.Where(u => u.UserName == userName).Count() > 0)
                    return true;
            }

            return false;
        }

        public IEnumerable<DbUserInfo> GetAllUsers()
        {
            List<DbUserInfo> result = new List<DbUserInfo>();

            try
            {
                Process p = InitPsqlProcess(AdminLogin, AdminPassword,
                    "select usename, usesysid, usecreatedb, usesuper, usecatupd from pg_catalog.pg_user");
                p.Start();
                p.WaitForExit();

                var output = p.StandardOutput.ReadToEnd();
                var error = p.StandardError.ReadToEnd();

                ValidatePsqlProcessOutput(output, error);

                //parse output
                string[] rows = output.Split(RowSeparator, 256, StringSplitOptions.RemoveEmptyEntries);

                foreach (var r in rows)
                {
                    string[] columns = r.Split(ColumnSeparator);

                    DbUserInfo userInfo = new DbUserInfo()
                    {
                        UserName = columns[0].Trim(),
                        SSID = Int32.Parse(columns[1].Trim()),
                        CanCreateDatabases = columns[2].Trim().ToLower() == "t" ? true : false,
                        IsSuperuser = columns[3].Trim().ToLower() == "t" ? true : false,
                        CanUpdateSystemCatalogs = columns[4].Trim().ToLower() == "t" ? true : false
                    };

                    result.Add(userInfo);
                }
            }
            catch (Exception ex)
            {
                if (ex is PsqlException)
                    throw ex;
            }

            return result;
        }

        public void CreateUserIfNotExists(string userName, string plainPassword, UserPermissionFlags options = UserPermissionFlags.None)
        {
            if (!UserExists(userName))
                CreateUser(userName, plainPassword, options);
        }

        public void CreateUser(string userName, string plainPassword, UserPermissionFlags options = UserPermissionFlags.None)
        {
            try
            {
                string additionalParams = ConvertUserPermissionsToString(options);

                string cmdText = String.Format("create user {0} with password '{1}' {2}", userName, plainPassword, additionalParams);

                Process p = InitPsqlProcess(AdminLogin, AdminPassword, cmdText);
                p.Start();
                p.WaitForExit();

                var output = p.StandardOutput.ReadToEnd();
                var error = p.StandardError.ReadToEnd();

                if (!String.IsNullOrWhiteSpace(error) || !CompareBanners(output, PsqlBannersEnum.CreateUser))
                    throw new PsqlException(error);
            }
            catch (Exception ex)
            {
                if (ex is PsqlException)
                    throw ex;
            }
        }

        public void ChangePassword(string userName, string newPlainPassword)
        {
            try
            {
                string cmdText = String.Format("alter user {0} with password '{1}'", userName, newPlainPassword);

                Process p = InitPsqlProcess(AdminLogin, AdminPassword, cmdText);
                p.Start();
                p.WaitForExit();

                var output = p.StandardOutput.ReadToEnd();
                var error = p.StandardError.ReadToEnd();

                if (!String.IsNullOrWhiteSpace(error) || !CompareBanners(output, PsqlBannersEnum.AlterUser))
                    throw new PsqlException(error);
            }
            catch (Exception ex)
            {
                if (ex is PsqlException)
                    throw ex;
            }
        }

        public void ChangeUserPermissions(string userName, UserPermissionFlags newOptions)
        {
            try
            {
                string additionalParams = ConvertUserPermissionsToString(newOptions);
                string cmdText = String.Format("alter user {0} {1}", userName, additionalParams);

                Process p = InitPsqlProcess(AdminLogin, AdminPassword, cmdText);
                p.Start();
                p.WaitForExit();

                var output = p.StandardOutput.ReadToEnd();
                var error = p.StandardError.ReadToEnd();

                if (!String.IsNullOrWhiteSpace(error) || !CompareBanners(output, PsqlBannersEnum.AlterUser))
                    throw new PsqlException(error);
            }
            catch (Exception ex)
            {
                if (ex is PsqlException)
                    throw ex;
            }
        }

        public void DropUser(string userName)
        {
            try
            {
                Process p = InitPsqlProcess(AdminLogin, AdminPassword, String.Format("drop user {0}", userName));
                p.Start();
                p.WaitForExit();

                var output = p.StandardOutput.ReadToEnd();
                var error = p.StandardError.ReadToEnd();

                if (!String.IsNullOrWhiteSpace(error) || !CompareBanners(output, PsqlBannersEnum.RemoveUser))
                    throw new PsqlException(error);
            }
            catch (Exception ex)
            {
                if (ex is PsqlException)
                    throw ex;
            }
        }

        #endregion

        #region Group management

        public IEnumerable<DbGroup> GetAllGroups()
        {
            List<DbGroup> result = new List<DbGroup>();

            try
            {
                Process p = InitPsqlProcess(AdminLogin, AdminPassword,
                    @"SELECT g.groname,g.grosysid,u.usename,u.usesysid,u.usecreatedb,u.usesuper,u.usecatupd " +
                    "from pg_group g,pg_user u where u.usesysid = any(g.grolist);");

                p.Start();
                p.WaitForExit();

                var output = p.StandardOutput.ReadToEnd();
                var error = p.StandardError.ReadToEnd();

                ValidatePsqlProcessOutput(output, error);

                //parse output
                string[] rows = output.Split(RowSeparator, 256, StringSplitOptions.RemoveEmptyEntries);

                List<RawGroupInfo> rawDataList = new List<RawGroupInfo>();

                foreach (var r in rows)
                {
                    string[] columns = r.Split(ColumnSeparator);

                    RawGroupInfo rawData = new RawGroupInfo()
                    {
                        GroupName = columns[0].Trim(),
                        GroupSID = Int32.Parse(columns[1].Trim()),
                        UserName = columns[2].Trim(),
                        UserSID = Int32.Parse(columns[3].Trim()),
                        UserCanCreateDb = columns[4].Trim().ToLower() == "t" ? true : false,
                        UserIsSuperuser = columns[5].Trim().ToLower() == "t" ? true : false,
                        UserCanUpdateCatalog = columns[6].Trim().ToLower() == "t" ? true : false
                    };

                    rawDataList.Add(rawData);
                }

                var groupedData = rawDataList.GroupBy(d => d.GroupSID);

                foreach (var g in groupedData)
                {
                    var firstItem = g.FirstOrDefault();
                    if (firstItem != null)
                    {
                        DbGroup group = new DbGroup()
                        {
                            Name = firstItem.GroupName,
                            SID = firstItem.GroupSID
                        };

                        List<DbUserInfo> groupUsers = new List<DbUserInfo>();
                        foreach (var i in g)
                        {
                            groupUsers.Add(new DbUserInfo()
                            {
                                UserName = i.UserName,
                                SSID = i.UserSID,
                                IsSuperuser = i.UserIsSuperuser,
                                CanUpdateSystemCatalogs = i.UserCanUpdateCatalog,
                                CanCreateDatabases = i.UserCanCreateDb
                            });
                        }

                        group.Users = groupUsers.ToArray();

                        result.Add(group);
                    }

                }

            }
            catch (Exception ex)
            {
                if (ex is PsqlException)
                    throw ex;
            }

            return result;
        }

        public void CreateGroup(string groupName)
        {
            CreateOrRemoveGroup(groupName, true);
        }

        public void DropGroup(string groupName)
        {
            CreateOrRemoveGroup(groupName, false);
        }

        private void CreateOrRemoveGroup(string groupName, bool create)
        {
            try
            {
                string cmdText = String.Format("{0} group {1}", create ? "create" : "drop", groupName);

                Process p = InitPsqlProcess(AdminLogin, AdminPassword, cmdText);
                p.Start();
                p.WaitForExit();

                var output = p.StandardOutput.ReadToEnd();
                var error = p.StandardError.ReadToEnd();

                PsqlBannersEnum banner = PsqlBannersEnum.CreateGroup;
                if (!create)
                    banner = PsqlBannersEnum.RemoveGroup;

                if (!String.IsNullOrWhiteSpace(error) || !CompareBanners(output, banner))
                    throw new PsqlException(error);
            }
            catch (Exception ex)
            {
                if (ex is PsqlException)
                    throw ex;
            }
        }

        public void AddUserToGroup(string groupName, string userName)
        {
            AddOrRemoveUserFromGroup(groupName, userName, true);
        }

        public void RemoveUserFromGroup(string groupName, string userName)
        {
            AddOrRemoveUserFromGroup(groupName, userName, false);
        }

        private void AddOrRemoveUserFromGroup(string groupName, string userName, bool addUser)
        {
            try
            {
                string cmdText = String.Format("alter group {0} {1} user {2}", groupName, addUser ? "add" : "drop", userName);

                Process p = InitPsqlProcess(AdminLogin, AdminPassword, cmdText);
                p.Start();
                p.WaitForExit();

                var output = p.StandardOutput.ReadToEnd();
                var error = p.StandardError.ReadToEnd();

                PsqlBannersEnum banner = PsqlBannersEnum.AddUserToGroup;
                if (!addUser)
                    banner = PsqlBannersEnum.RemoveUserFromGroup;

                if (!String.IsNullOrWhiteSpace(error) || !CompareBanners(output, banner))
                    throw new PsqlException(error);
            }
            catch (Exception ex)
            {
                if (ex is PsqlException)
                    throw ex;
            }
        }

        #endregion

        #region Privileges management

        public void GrantPrivilegesToUser(string userName, string objectName, DbPrivileges flags)
        {
            GrantOrRevokePrivilegesImpl(true, objectName, flags, null, userName);
        }

        public void RevokePrivilegesFromUser(string userName, string objectName, DbPrivileges flags)
        {
            GrantOrRevokePrivilegesImpl(false, objectName, flags, null, userName);
        }

        public void GrantPrivilegesToGroup(string groupName, string objectName, DbPrivileges flags)
        {
            GrantOrRevokePrivilegesImpl(true, objectName, flags, groupName, null);
        }

        public void RevokePrivilegesFromGroup(string groupName, string objectName, DbPrivileges flags)
        {
            GrantOrRevokePrivilegesImpl(false, objectName, flags, groupName, null);
        }

        public void GrantPublicPrivileges(string objectName, DbPrivileges flags)
        {
            GrantOrRevokePrivilegesImpl(true, objectName, flags);
        }

        public void RevokePublicPrivileges(string objectName, DbPrivileges flags)
        {
            GrantOrRevokePrivilegesImpl(false, objectName, flags);
        }

        private void GrantOrRevokePrivilegesImpl(bool grant, string objectName, DbPrivileges flags, string groupName = null, string userName = null)
        {
            /*
             * GRANT privilege [, ...] ON object [, ...]
             *   TO { PUBLIC | username | GROUP groupname }
             */

            string privilegesStr = flags.ToString();
            string cmdTypeStr = grant ? "grant" : "revoke";

            try
            {
                string cmdText = String.Empty;

                if (String.IsNullOrWhiteSpace(groupName) && String.IsNullOrWhiteSpace(userName))
                    cmdText = String.Format("grant {0} on {1} to public", privilegesStr, objectName);
                else
                {
                    if (!String.IsNullOrWhiteSpace(groupName))
                        cmdText = String.Format("grant {0} on {1} to group {2}", privilegesStr, objectName, groupName);
                    else
                        if (!String.IsNullOrWhiteSpace(userName))
                        {
                            cmdText = String.Format("grant {0} on {1} to {2}", privilegesStr, objectName, userName);
                        }
                }


                Process p = InitPsqlProcess(AdminLogin, AdminPassword, cmdText);
                p.Start();
                p.WaitForExit();

                var output = p.StandardOutput.ReadToEnd();
                var error = p.StandardError.ReadToEnd();

                if (!String.IsNullOrWhiteSpace(error) /*|| !CompareBanners(output, banner)*/)
                    throw new PsqlException(error);
            }
            catch (Exception ex)
            {
                if (ex is PsqlException)
                    throw ex;
            }
        }

        #endregion

        #region Schema management

        public string[] GetTableNames(string dbName)
        {
            List<string> result = new List<string>();

            try
            {
                Process p = InitPsqlProcess(AdminLogin, AdminPassword, "\\dt", dbName);
                p.Start();
                p.WaitForExit();

                var output = p.StandardOutput.ReadToEnd();
                var error = p.StandardError.ReadToEnd();

                ValidatePsqlProcessOutput(output, error);

                string[] rows = output.Split(RowSeparator, 2048, StringSplitOptions.RemoveEmptyEntries);

                foreach (var r in rows)
                {
                    string[] columns = r.Split(ColumnSeparator);
                    result.Add(columns[1].Trim());
                }
            }
            catch (Exception ex)
            {
                if (ex is PsqlException)
                    throw ex;
            }

            return result.ToArray();
        }

        public ITable GetTableSchema(string dbName, string tableName)
        {
            ITable result = null;

            try
            {
                Process p = InitPsqlProcess(AdminLogin, AdminPassword, String.Format("\\d {0}", tableName), dbName);
                p.Start();
                p.WaitForExit();

                var output = p.StandardOutput.ReadToEnd();
                var error = p.StandardError.ReadToEnd();

                ValidatePsqlProcessOutput(output, error);

                string[] rows = output.Split(RowSeparator, 256, StringSplitOptions.RemoveEmptyEntries);

                ISchemaParser schemaParser = new SchemaParser();
                ITable table = new Table(tableName);

                foreach (var r in rows)
                {
                    string[] columns = r.Split(ColumnSeparator);
                    string columnName = columns[0].Trim();
                    ColumnDataInfo columnInfo = schemaParser.Parse(columns[1].Trim(), columns[2].Trim());

                    table.AddColumn(new Column(columnName, columnInfo));
                }

                ISchemaParser parser = new SchemaParser();

                var constraints = GetTableRelations(dbName, tableName);
                foreach (var c in constraints)
                {
                    IConstraint newRelation = parser.ParseConstraint(tableName, c.Name, c.ConstraintInfo);
                    if (newRelation != null)
                        table.AddConstraint(newRelation);
                }

                result = table;
            }
            catch (Exception ex)
            {
                if (ex is PsqlException)
                    throw ex;
            }

            return result;
        }

        public void CreateTable(string dbName, ITable table)
        {
            try
            {
                ISchemaConverter converter = new SchemaConverter();
                string tableDDL = converter.GetDDL(table);

                Process p = InitPsqlProcess(AdminLogin, AdminPassword, tableDDL, dbName);
                p.Start();
                p.WaitForExit();

                var output = p.StandardOutput.ReadToEnd();
                var error = p.StandardError.ReadToEnd();

                if ((!String.IsNullOrWhiteSpace(error) && !error.Contains("NOTICE") && error.Contains("ERROR")) || // error may contain notices -- this isn't error
                    !CompareBanners(output, PsqlBannersEnum.CreateTable))
                    throw new PsqlException(error);
            }
            catch (Exception ex)
            {
                if (ex is PsqlException)
                    throw ex;
            }
        }

        private IEnumerable<RawConstraint> GetTableRelations(string dbName, string tableName)
        {
            List<RawConstraint> result = new List<RawConstraint>();

            try
            {
                string cmdText = String.Format(@"SELECT conname, pg_catalog.pg_get_constraintdef(r.oid, true) as condef " +
                                               "FROM pg_catalog.pg_constraint r " +
                                               "WHERE r.conrelid = " +
                                               "( SELECT oid FROM pg_catalog.pg_class WHERE relname ~ '^({0})$' AND pg_catalog.pg_table_is_visible(oid))", tableName);

                Process p = InitPsqlProcess(AdminLogin, AdminPassword, cmdText, dbName);
                p.Start();
                p.WaitForExit();

                var output = p.StandardOutput.ReadToEnd();
                var error = p.StandardError.ReadToEnd();

                ValidatePsqlProcessOutput(output, error);

                string[] rows = output.Split(RowSeparator, 256, StringSplitOptions.RemoveEmptyEntries);

                foreach (var r in rows)
                {
                    string[] columns = r.Split(ColumnSeparator);

                    RawConstraint relationInfo = new RawConstraint()
                    {
                        Name = columns[0].Trim(),
                        ConstraintInfo = columns[1].Trim()
                    };

                    result.Add(relationInfo);
                }

            }
            catch (Exception ex)
            {
                if (ex is PsqlException)
                    throw ex;
            }

            return result;

        }

        #endregion

        #endregion

        private Process InitPsqlProcess(string adminLogin, string adminPassword, string arguments, string dbName = null,
            PsqlProcessFlags flags = PsqlProcessFlags.None)
        {
            string value = Environment.GetEnvironmentVariable(PgpassVariable);
            if (String.IsNullOrWhiteSpace(value))
            {
                Environment.SetEnvironmentVariable(PgpassVariable, adminPassword);
            }
            Environment.SetEnvironmentVariable(PgClienEncodingVariable, PgClienEncoding);

            Process p = new Process();
            p.StartInfo = new ProcessStartInfo(PsqlPath);
            p.StartInfo.UseShellExecute = false;
            p.StartInfo.RedirectStandardOutput = true;
            p.StartInfo.RedirectStandardError = true;
            p.StartInfo.CreateNoWindow = true;

            string dbNameBanner = dbName == null ? null : "-d " + dbName;

            switch (flags)
            {
                case PsqlProcessFlags.DisableCommandQuotes:
                    p.StartInfo.Arguments = String.Format("--tuples-only -U {0} {1} -c {2}", adminLogin, dbNameBanner, arguments);
                    break;
                case PsqlProcessFlags.DisableCommandFlag:
                    p.StartInfo.Arguments = String.Format("--tuples-only -U {0} {1} \"{2}\"", adminLogin, dbNameBanner, arguments);
                    break;
                case PsqlProcessFlags.DisableCommandFlag | PsqlProcessFlags.DisableCommandQuotes:
                    p.StartInfo.Arguments = String.Format("--tuples-only -U {0} {1} {2}", adminLogin, dbNameBanner, arguments);
                    break;
                case PsqlProcessFlags.CleanMode:
                    p.StartInfo.Arguments = String.Format("{0}", arguments);
                    break;
                case PsqlProcessFlags.ExternalFile:
                    var tempFile = Path.GetTempFileName();
                    File.WriteAllText(tempFile, arguments);
                    p.StartInfo.Arguments = String.Format("--tuples-only -U {0} {1} -f {2}", adminLogin, dbNameBanner, tempFile);
                    break;
                case PsqlProcessFlags.None:
                default:
                    p.StartInfo.Arguments = String.Format("--tuples-only -U {0} {1} -c\"{2}\"", adminLogin, dbNameBanner, arguments);
                    break;
            }

            return p;
        }

        private void ValidatePsqlProcessOutput(string output, string error)
        {
            if (!String.IsNullOrWhiteSpace(error))
            {
                throw new PsqlException(error);
            }
        }

        private bool CompareBanners(string bannerStr, PsqlBannersEnum bannerType)
        {
            return psqlBanners.CompareBanners(bannerStr, bannerType);
        }

        private string ConvertUserPermissionsToString(UserPermissionFlags options)
        {
            string additionalParams = String.Empty;

            switch (options)
            {
                case UserPermissionFlags.CreateDb:
                    additionalParams = "createdb";
                    break;
                case UserPermissionFlags.CreateUser:
                    additionalParams = "createuser";
                    break;
                case UserPermissionFlags.NoCreateDb:
                    additionalParams = "nocreatedb";
                    break;
                case UserPermissionFlags.NoCreateUser:
                    additionalParams = "nocreateuser";
                    break;
                case UserPermissionFlags.CreateDb | UserPermissionFlags.NoCreateUser:
                    additionalParams = "createdb nocreateuser";
                    break;
                case UserPermissionFlags.CreateUser | UserPermissionFlags.NoCreateDb:
                    additionalParams = "createuser nocreatedb";
                    break;
                case UserPermissionFlags.CreateDb | UserPermissionFlags.CreateUser:
                    additionalParams = "createdb createuser";
                    break;
                case UserPermissionFlags.NoCreateDb | UserPermissionFlags.NoCreateUser:
                    additionalParams = "nocreatedb nocreateuser";
                    break;
                default:
                    additionalParams = String.Empty;
                    break;
            }

            return additionalParams;
        }

        #region Private fields

        private PsqlBanners psqlBanners;

        #endregion
    }
}
